/***********************************************************************************
Copy right:	    hqyj Tech.
Author:         jiaoyue
Date:           2023.07.01
Description:    http请求处理
***********************************************************************************/

#include <sys/types.h>
#include <sys/socket.h>
#include "custom_handle.h"  //共享内存封装库
#include "msg_queue_peer.h" //消息队列封装库
#include "shmem.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h" //cJSON库
#include <pthread.h>
#include <time.h>
#include <sys/msg.h> //消息队列
#include <errno.h>

// // 消息队列结构体
// struct msgbuf
// {
//     long mtype;
//     char mdata[256];
// };

#define KB 1024
#define HTML_SIZE (64 * KB)

// 普通的文本回复需要增加html头部
#define HTML_HEAD "Content-Type: text/html\r\n" \
                  "Connection: close\r\n"
// JSON响应头部
#define JSON_HEAD "HTTP/1.1 200 OK\r\n"                \
                  "Content-Type: application/json\r\n" \
                  "Access-Control-Allow-Origin: *\r\n" \
                  "Connection: close\r\n"
// JSON错误响应头部（带状态码）
#define JSON_ERROR_HEAD(status) "HTTP/1.1 " #status " \r\n"          \
                                "Content-Type: application/json\r\n" \
                                "Access-Control-Allow-Origin: *\r\n" \
                                "Connection: close\r\n"
DeviceData *device = NULL;
extern DeviceData *shm_addr;
extern void print_shared_memory_data();
static struct shm_param para;

// 全局变量保护锁（多线程访问共享内存时使用）
static pthread_mutex_t shmem_mutex = PTHREAD_MUTEX_INITIALIZER;

// 新增：发送JSON格式响应（通用函数）  看一下
static void send_json_response(int sock, int status_code, const char *json)
{
    const char *status_text = NULL;
    // 根据状态码设置对应的状态文本
    switch (status_code)
    {
    case 200:
        status_text = "OK";
        break;
    case 400:
        status_text = "Bad Request";
        break;
    case 500:
        status_text = "Internal Server Error";
        break;
    default:
        status_text = "Unknown Status";
    }

    size_t json_len = strlen(json);
    printf("send_json_response: JSON长度 = %zu 字节\n", json_len);

    char header[1024];
    int header_len = snprintf(header, sizeof(header),
                              "HTTP/1.1 %d %s\r\n"
                              "Content-Type: application/json\r\n"
                              "Access-Control-Allow-Origin: *\r\n"
                              "Connection: close\r\n"
                              "Content-Length: %zu\r\n"
                              "\r\n",
                              status_code, status_text, json_len);

    if (header_len < 0 || (size_t)header_len >= sizeof(header))
    {
        printf("send_json_response: 响应头溢出!header_len = %d\n", header_len);
        return;
    }
    printf("send_json_response: 响应头内容 = \n%s\n", header);

    // 发送响应头（处理EAGAIN错误）
    ssize_t total_sent = 0;
    while (total_sent < header_len)
    {
        ssize_t sent = send(sock, header + total_sent, header_len - total_sent, 0);
        if (sent < 0)
        {
            // 忽略暂时无法发送的错误，重试
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                usleep(1000); // 等待1ms后重试
                continue;
            }
            perror("send_json_response: 发送响应头失败");
            return;
        }
        total_sent += sent;
    }
    printf("send_json_response: 响应头发送完成，共 %zd 字节\n", total_sent);

    // 发送JSON数据（处理EAGAIN错误）
    total_sent = 0;
    while (total_sent < json_len)
    {
        ssize_t sent = send(sock, json + total_sent, json_len - total_sent, 0);
        if (sent < 0)
        {
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                usleep(1000);
                continue;
            }
            perror("send_json_response: 发送JSON失败");
            return;
        }
        total_sent += sent;
    }
    printf("send_json_response: JSON发送完成,共 %zd 字节\n", total_sent);

    // 关键：等待数据发送完成后再关闭连接
    shutdown(sock, SHUT_WR); // 关闭写方向，告知客户端数据已发送完毕
    usleep(100000);          // 等待100ms，确保数据通过网络传输
}
// 处理打印共享内存数据的请求
static int handle_print_shared_memory(int sock)
{
    // 调用打印函数
    print_shared_memory_data();

    // 给客户端返回响应
    const char *response = "HTTP/1.1 200 OK\r\n"
                           "Content-Type: text/plain\r\n"
                           "Connection: close\r\n"
                           "\r\n"
                           "共享内存数据已打印到服务器终端";
    send(sock, response, strlen(response), 0);
    return 0;
}

/**
 * @brief 数据转换成JSON格式
 * @param
 * @return
 */
char *shmem_to_json()
{
    // 加锁保护共享内存访问
    pthread_mutex_lock(&shmem_mutex);
    printf("shmem_to_json: 开始生成JSON\n");
    if (!device)
    {
        pthread_mutex_unlock(&shmem_mutex);
        printf("shmem_to_json: shm_addr为空\n");
        return strdup("{\"error\": \"共享内存未初始化\"}");
    }

    cJSON *root = cJSON_CreateObject();
    if (!root)
    {
        pthread_mutex_unlock(&shmem_mutex);
        printf("shmem_to_json: 创建root失败\n");
        return strdup("{\"error\": \"创建JSON对象失败\"}");
    }
    printf("shmem_to_json: 创建root成功\n");
    // 控制多长时间发送一次
    // sleep(3);
    // 处理STM32数据
    // cJSON *root = cJSON_CreateObject();
    Stm32Data *stm32 = device->stm32_list;
    // stm32 json
    cJSON *stm32Arry = cJSON_CreateArray();
    for (size_t i = 0; i < device->stm32_count; i++)
    {

        cJSON *obj = cJSON_CreateObject();

        cJSON *keyValue = cJSON_CreateNumber(device->stm32_list[i].key);
        cJSON_AddItemToObject(obj, "key", keyValue);

        cJSON *nameValue = cJSON_CreateString(device->stm32_list[i].name);
        cJSON_AddItemToObject(obj, "name", nameValue);

        cJSON *typeValue = cJSON_CreateNumber(device->stm32_list[i].type);
        cJSON_AddItemToObject(obj, "type", typeValue);

        cJSON *typeStataValue = cJSON_CreateNumber(device->stm32_list[i].typeStata);
        cJSON_AddItemToObject(obj, "typeStata", typeStataValue);

        cJSON *valueValue = cJSON_CreateNumber(device->stm32_list[i].value);
        cJSON_AddItemToObject(obj, "value", valueValue);

        cJSON *floatValueValue = cJSON_CreateNumber(device->stm32_list[i].floatValue);
        cJSON_AddItemToObject(obj, "floatValue", floatValueValue);

        cJSON_AddItemToArray(stm32Arry, obj);
    }
    cJSON *data_obj = cJSON_CreateObject();
    cJSON_AddItemToObject(data_obj, "data", stm32Arry);
    cJSON *stm32Obj = cJSON_CreateObject(); //
    cJSON_AddItemToObject(root, "stm32", data_obj);

    // modbus json
    cJSON *modbusArry = cJSON_CreateArray();
    for (size_t i = 0; i < device->modbus_count; i++)

    {

        cJSON *obj = cJSON_CreateObject();

        cJSON *keyValue = cJSON_CreateNumber(device->modbus_list[i].key);
        cJSON_AddItemToObject(obj, "key", keyValue);

        cJSON *nameValue = cJSON_CreateString(device->modbus_list[i].name);
        cJSON_AddItemToObject(obj, "name", nameValue);

        cJSON *typeValue = cJSON_CreateNumber(device->modbus_list[i].type);
        cJSON_AddItemToObject(obj, "type", typeValue);

        cJSON *typeStataValue = cJSON_CreateNumber(device->modbus_list[i].typeStata);
        cJSON_AddItemToObject(obj, "typeStata", typeStataValue);

        cJSON *valueValue = cJSON_CreateNumber(device->modbus_list[i].value);
        cJSON_AddItemToObject(obj, "value", valueValue);

        cJSON *addrValue = cJSON_CreateNumber(device->modbus_list[i].addr);
        cJSON_AddItemToObject(obj, "addr", addrValue);

        cJSON_AddItemToArray(modbusArry, obj);
    }

    cJSON *modbusData = cJSON_CreateObject();
    cJSON_AddItemToObject(modbusData, "data", modbusArry);
    cJSON *modbusObj = cJSON_CreateObject();
    cJSON_AddItemToObject(root, "modbus", modbusData);

    cJSON *metaArry = cJSON_CreateArray();
    for (size_t i = 0; i < device->meta_count; i++)

    {

        cJSON *obj = cJSON_CreateObject();

        cJSON *keyValue = cJSON_CreateNumber(device->meta_list[i].key);

        cJSON_AddItemToObject(obj, "key", keyValue);

        cJSON *nameValue = cJSON_CreateString(device->meta_list[i].name);

        cJSON_AddItemToObject(obj, "name", nameValue);

        cJSON *typeValue = cJSON_CreateNumber(device->meta_list[i].type);

        cJSON_AddItemToObject(obj, "type", typeValue);

        cJSON *typeStataValue = cJSON_CreateNumber(device->meta_list[i].typeStata);

        cJSON_AddItemToObject(obj, "typeStata", typeStataValue);

        cJSON *valueValue = cJSON_CreateNumber(device->meta_list[i].value);
        cJSON_AddItemToObject(obj, "value", valueValue);

        cJSON *addrValue = cJSON_CreateNumber(device->meta_list[i].addr);
        cJSON_AddItemToObject(obj, "addr", addrValue);

        cJSON_AddItemToArray(metaArry, obj);
    }

    cJSON *metaData = cJSON_CreateObject();
    cJSON_AddItemToObject(metaData, "data", metaArry);
    cJSON *metaObj = cJSON_CreateObject();
    cJSON_AddItemToObject(root, "metaServer", metaData);

    // 添加时间戳
    cJSON_AddNumberToObject(root, "timestamp", time(NULL));

    printf("shmem_to_json: 生成stm32数组完成\n"); // 新增日志
    // 生成JSON字符串（无格式压缩版）
    char *json = cJSON_PrintUnformatted(root);
    if (!json)
    {
        printf("shmem_to_json: JSON序列化失败\n"); // 新增日志
        json = strdup("{\"error\": \"JSON序列化失败\"}");
    }
    else
    {
        printf("shmem_to_json: 生成JSON成功: %s\n", json); // 新增日志
    }

    // 清理资源
    cJSON_Delete(root);
    pthread_mutex_unlock(&shmem_mutex); // 解锁

    return json;
}

// 处理获取共享内存数据的请求（客户端轮询）
static int handle_get_shmem_data(int sock)
{
    // // 生成JSON数据
    // char *json_str = shmem_to_json();
    // if (!json_str)
    // {
    //     const char *error = "{\"error\": \"生成数据失败\"}";
    //     send(sock, error, strlen(error), 0);
    //     return -1;
    // }

    // // 只发送JSON数据，不包含HTTP头   网页只解析JSON
    // send(sock, json_str, strlen(json_str), 0);

    // // 释放资源
    // free(json_str);
    // printf("已响应客户端数据请求\n");

    // return 0;
    // 生成JSON数据
    char *json_str = shmem_to_json();
    if (!json_str)
    {
        const char *error = "{\"error\": \"生成数据失败\"}";
        send_json_response(sock, 500, error); // 使用标准响应函数
        return -1;
    }

    // 使用正确的JSON响应函数发送完整HTTP响应（包含响应头）
    send_json_response(sock, 200, json_str);

    // 释放资源
    free(json_str);
    printf("已响应客户端数据请求\n");

    return 0;
}
/**
 * @brief 消息队列,处理设备控制请求（核心函数）接受网页的JSON格式控制指令
 * @param input
 * @return
 */
static int handle_control_device(int sock, const char *input)
{
    // 1. 验证输入数据不为空
    if (!input || strlen(input) == 0)
    {
        const char *error = "{\"status\":-1,\"msg\":\"请求数据为空\"}";
        send_json_response(sock, 400, error);
        printf("控制请求：输入数据为空\n");
        return -1;
    }

    // 2. 简单解析根节点，判断设备类型
    cJSON *root = cJSON_Parse(input);
    if (root == NULL)
    {
        printf("JSON parse error: %s\n", cJSON_GetErrorPtr());
        const char *error = "{\"status\":-1,\"msg\":\"JSON格式错误\"}";
        send_json_response(sock, 400, error);
        return -1;
    }

    // 定义变量记录处理结果
    int ret = -1;
    const char *queue_name = NULL;
    long msg_type = 0;
    char device_type[16] = {0};

    // 3. 判断设备类型，确定消息队列名称
    if (cJSON_GetObjectItem(root, "stm32"))
    {
        queue_name = "stm32";
        msg_type = 1;
        strcpy(device_type, "stm32");
    }
    else if (cJSON_GetObjectItem(root, "modbus"))
    {
        queue_name = "modbus";
        msg_type = 2;
        strcpy(device_type, "modbus");
    }
    else if (cJSON_GetObjectItem(root, "metaServer"))
    {
        queue_name = "metaServer";
        msg_type = 3;
        strcpy(device_type, "metaServer");
    }
    else
    {
        const char *error = "{\"status\":-1,\"msg\":\"未支持的设备类型\"}";
        send_json_response(sock, 400, error);
        cJSON_Delete(root);
        return -1;
    }

    // 4. 直接将原始JSON转发到对应消息队列
    struct msgbuf msg;
    msg.mtype = msg_type;

    if (strcmp(device_type, "modbus") == 0)
    {
        cJSON *modbus_obj = cJSON_GetObjectItem(root, "modbus");
        if (modbus_obj)
        {
            cJSON *key_obj = cJSON_GetObjectItem(modbus_obj, "key");
            if (key_obj)
            {
                int modbus_key = key_obj->valueint;
                // 检查key是否在Modbus端支持的范围内（2001~2006）
                if (!(modbus_key >= 2001 && modbus_key <= 2006))
                {
                    const char *error = "{\"status\":-1,\"msg\":\"Modbus设备key无效（仅支持2001-2006）\"}";
                    send_json_response(sock, 400, error);
                    printf("Modbus无效key: %d,拒绝转发\n", modbus_key);
                    cJSON_Delete(root);
                    return -1;
                }
            }
        }
    }
    // 确保JSON数据不超过消息缓冲区大小
    if (strlen(input) >= sizeof(msg.mdata))
    {
        const char *error = "{\"status\":-1,\"msg\":\"指令过长\"}";
        send_json_response(sock, 400, error);
        cJSON_Delete(root);
        return -1;
    }

    // 复制原始JSON到消息缓冲区
    strncpy(msg.mdata, input, sizeof(msg.mdata) - 1);

    // 打印转发信息
    printf("\n===== 转发到消息队列的指令 =====");
    printf("\n设备类型: %s", device_type);
    printf("\n队列名称: %s", queue_name);
    printf("\n消息类型: %ld", msg.mtype);
    printf("\n原始JSON内容: %s", msg.mdata);
    printf("\n消息长度: %zu 字节\n", strlen(msg.mdata));

    // 在“发送消息到队列”前，新增延迟逻辑（仅对Modbus设备生效）
    if (strcmp(device_type, "modbus") == 0)
    {
        printf("Modbus消息延迟150ms发送,避开信号量占用...\n");
        usleep(150 * 1000); // 150ms延迟（可根据实际情况调整，100~200ms均可）
    }
    // 发送消息到队列
    ret = msg_queue_send(queue_name, (char *)&msg, sizeof(msg), 0);
    if (ret == -1)
    {
        perror("msg_queue_send failed");
        const char *error = "{\"status\":-1,\"msg\":\"消息发送失败\"}";
        send_json_response(sock, 500, error);
        cJSON_Delete(root);
        return -1;
    }
    printf("******************=====================%d\n", ret);
    // 5. 发送成功响应
    const char *success = "{\"status\":0,\"msg\":\"指令已转发\"}";
    send_json_response(sock, 200, success);

    // 清理资源
    cJSON_Delete(root);
    return 0;
}

// static int handle_login(int sock, const char *input)
// {
//     char reply_buf[HTML_SIZE] = {0};
//     char *uname = strstr(input, "username=");
//     uname += strlen("username=");
//     char *p = strstr(input, "password");
//     *(p - 1) = '\0';
//     printf("username = %s\n", uname);

//     char *passwd = p + strlen("password=");
//     printf("passwd = %s\n", passwd);

//     if (strcmp(uname, "admin") == 0 && strcmp(passwd, "admin") == 0)
//     { // 登录成功：向 reply_buf 写入「存储用户名到localStorage」的脚本
//         sprintf(reply_buf, "<script>localStorage.setItem('usr_user_name', '%s');</script>", uname);
//         // 接着拼接「跳转到首页」的脚本（这里用 strcat 是因为前面 snprintf 已确保没溢出）
//         strcat(reply_buf, "<script>window.location.href = '/control.html';</script>");
//         send(sock, reply_buf, strlen(reply_buf), 0);
//     }
//     else
//     {
//         printf("web login failed\n");

//         //"用户名或密码错误"提示，chrome浏览器直接输送utf-8字符流乱码，没有找到太好解决方案，先过渡
//         char out[128] = {0xd3, 0xc3, 0xbb, 0xa7, 0xc3, 0xfb, 0xbb, 0xf2, 0xc3, 0xdc, 0xc2, 0xeb, 0xb4, 0xed, 0xce, 0xf3};
//         sprintf(reply_buf, "<script charset='gb2312'>alert('%s');</script>", out);
//         strcat(reply_buf, "<script>window.location.href = '/login.html';</script>");
//         send(sock, reply_buf, strlen(reply_buf), 0);
//     }

//     return 0;
// }
static int handle_login(int sock, const char *input)
{
    char reply_buf[HTML_SIZE] = {0};
    char *uname = strstr(input, "username=");
    if (!uname)
    {
        const char *error_html = "HTTP/1.1 400 Bad Request\r\n"
                                 "Content-Type: text/html; charset=utf-8\r\n"
                                 "Connection: close\r\n\r\n"
                                 "<script>alert('参数错误');window.location.href='/login.html';</script>";
        send_json_response(sock, 400, error_html);
        return -1;
    }
    uname += strlen("username=");
    char *p = strstr(input, "password");
    if (!p)
    {
        const char *error_html = "HTTP/1.1 400 Bad Request\r\n"
                                 "Content-Type: text/html; charset=utf-8\r\n"
                                 "Connection: close\r\n\r\n"
                                 "<script>alert('参数错误');window.location.href='/login.html';</script>";
        send_json_response(sock, 400, error_html);
        return -1;
    }
    *(p - 1) = '\0';
    printf("username = %s\n", uname);

    char *passwd = p + strlen("password=");
    printf("passwd = %s\n", passwd);

    if (strcmp(uname, "admin") == 0 && strcmp(passwd, "admin") == 0)
    {
        // 关键修复：移除control.html后的空格，确保路径正确
        char success_html[1024];
        sprintf(success_html,
                "<script>localStorage.setItem('usr_user_name', '%s');</script>"
                "<script>window.location.href = '/index.html';</script>", // 这里移除了空格
                uname);
        send_json_response(sock, 200, success_html);
    }
    else
    {
        printf("web login failed\n");
        const char *error_html = "<script>alert('用户名或密码错误');window.location.href='/login.html';</script>";
        send_json_response(sock, 401, error_html);
    }

    return 0;
}

static int handle_add(int sock, const char *input)
{
    int number1, number2;

    // input必须是"data1=1data2=6"类似的格式，注意前端过来的字符串会有双引号
    sscanf(input, "\"data1=%ddata2=%d\"", &number1, &number2);
    printf("num1 = %d\n", number1);

    char reply_buf[HTML_SIZE] = {0};
    printf("num = %d\n", number1 + number2);
    sprintf(reply_buf, "%d", number1 + number2);
    printf("resp = %s\n", reply_buf);
    send(sock, reply_buf, strlen(reply_buf), 0);

    return 0;
}

/**
 * @brief 处理自定义请求，在这里添加进程通信
 * @param input
 * @return
 */
int parse_and_process(int sock, const char *query_string, const char *input)
{
    // 处理获取共享内存数据的请求（客户端轮询）
    if (query_string && strstr(query_string, "action=get_shmem_data"))
    {
        return handle_get_shmem_data(sock);
    }

    // 处理打印共享内存数据的请求
    if (strstr(input, "action=print_shmem") ||
        (query_string && strstr(query_string, "action=print_shmem")))
    {
        return handle_print_shared_memory(sock);
    }

    // query_string不一定能用的到

    // 先处理登录操作
    if (strstr(input, "username=") && strstr(input, "password="))
    {
        return handle_login(sock, input);
    }
    // 处理求和请求
    else if (strstr(input, "data1=") && strstr(input, "data2="))
    {
        return handle_add(sock, input);
    }
    else if (query_string && strstr(query_string, "action=control_device"))
    {
        // 处理设备控制请求
        return handle_control_device(sock, input);
    }
    else // 剩下的都是json请求，这个和协议有关了
    {
        // 构建要回复的JSON数据
        const char *json_response = "{\"message\": \"Hello, client!\"}";

        // 发送HTTP响应给客户端
        send(sock, json_response, strlen(json_response), 0);
    }

    return 0;
}

/**
 * @brief 共享内存
 * @param
 * @return  共享内存地址
 */
DeviceData *init_shared_memory()
{ // 要返回共享内存的地址
    int ret = -1;

    // // 注意进程双方共享内存的大小一致
    // ret = shm_init(&para, "main.c", 1024);    //看网关里的名字  大小

    // 初始化共享内存参数（键值为"main.c"，大小为DeviceData结构体大小）
    ret = shm_init(&para, "main.c", sizeof(DeviceData));
    if (ret < 0)
    {
        perror("shm_init failed");
        // device_data_free(device);
        return NULL;
    }

    //  获取共享内存地址
    DeviceData *shm_addr = (DeviceData *)shm_getaddr(&para);
    if (!shm_addr)
    {
        perror("shm_getaddr failed");
        // device_data_free(device);
        return NULL;
    }

    // 初始化全局设备指针
    device = shm_addr; // 全局指针指向共享内存
    printf("共享内存初始化成功，大小: %zu 字节\n", sizeof(DeviceData));
    return shm_addr;

    // 如果这个内存一直要用，那么不要删除
    // shm_del(&para);
}